package org.lc.stk.security.config;

import org.lc.stk.security.jwt.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * Spring Security 安全配置类
 *
 * &lt;p&gt;此配置类定义了整个应用的安全策略,包括:&lt;/p&gt;
 * &lt;ul&gt;
 *   &lt;li&gt;认证方式: 基于JWT的无状态认证&lt;/li&gt;
 *   &lt;li&gt;安全过滤器链配置: 定义请求的安全处理流程&lt;/li&gt;
 *   &lt;li&gt;资源访问规则: 配置URL的访问权限&lt;/li&gt;
 *   &lt;li&gt;方法级安全: 启用@PreAuthorize等注解支持&lt;/li&gt;
 *   &lt;li&gt;CSRF防护: 对API禁用,对H2-Console特殊处理&lt;/li&gt;
 *   &lt;li&gt;Session管理: 采用无状态会话策略&lt;/li&gt;
 * &lt;/ul&gt;
 *
 * &lt;p&gt;主要注解说明:&lt;/p&gt;
 * &lt;ul&gt;
 *   &lt;li&gt;{@code @Configuration}: 标识这是一个Spring配置类&lt;/li&gt;
 *   &lt;li&gt;{@code @EnableWebSecurity}: 启用Spring Security的Web安全支持&lt;/li&gt;
 *   &lt;li&gt;{@code @EnableMethodSecurity}: 启用方法级安全控制,支持@PreAuthorize等注解&lt;/li&gt;
 * &lt;/ul&gt;
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(
    prePostEnabled = true,
    securedEnabled = true,
    jsr250Enabled = true
)
public class SecurityConfig {

    /**
     * JWT认证过滤器
     *
     * &lt;p&gt;用于处理基于JWT的身份认证,在{@link UsernamePasswordAuthenticationFilter}之前执行。
     * 其职责包括:&lt;/p&gt;
     * &lt;ul&gt;
     *   &lt;li&gt;从请求头中提取JWT Token&lt;/li&gt;
     *   &lt;li&gt;验证Token的有效性&lt;/li&gt;
     *   &lt;li&gt;解析Token中的用户信息&lt;/li&gt;
     *   &lt;li&gt;将认证信息设置到SecurityContext中&lt;/li&gt;
     * &lt;/ul&gt;
     */
    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
        this.jwtAuthenticationFilter = jwtAuthenticationFilter;
    }

    /**
     * 配置Spring Security的安全过滤器链
     *
     * &lt;p&gt;定义了HTTP请求的安全处理流程，包括以下配置:&lt;/p&gt;
     * &lt;ul&gt;
     *   &lt;li&gt;CSRF防护:
     *     &lt;ul&gt;
     *       &lt;li&gt;禁用全局CSRF保护(因为使用JWT认证)&lt;/li&gt;
     *       &lt;li&gt;为H2-Console特别配置,允许其在开发环境中正常使用&lt;/li&gt;
     *     &lt;/ul&gt;
     *   &lt;/li&gt;
     *   &lt;li&gt;安全响应头:
     *     &lt;ul&gt;
     *       &lt;li&gt;设置H2-Console的X-Frame-Options为SAMEORIGIN,允许同源页面嵌入&lt;/li&gt;
     *     &lt;/ul&gt;
     *   &lt;/li&gt;
     *   &lt;li&gt;请求授权规则:
     *     &lt;ul&gt;
     *       &lt;li&gt;允许/api/auth/**公开访问(用于登录注册等)&lt;/li&gt;
     *       &lt;li&gt;允许H2-Console访问(开发环境)&lt;/li&gt;
     *       &lt;li&gt;允许Swagger/OpenAPI文档访问&lt;/li&gt;
     *       &lt;li&gt;其他请求需要认证&lt;/li&gt;
     *     &lt;/ul&gt;
     *   &lt;/li&gt;
     *   &lt;li&gt;会话管理: 配置为无状态(STATELESS),不使用Session&lt;/li&gt;
     *   &lt;li&gt;过滤器: 将JWT过滤器添加到用户名密码认证过滤器之前&lt;/li&gt;
     * &lt;/ul&gt;
     *
     * @param http HTTP安全配置对象
     * @return 配置完成的SecurityFilterChain
     * @throws Exception 配置过程中的异常
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers(new AntPathRequestMatcher("/h2-console/**"))
                .disable())
            .headers(headers -> headers
                .addHeaderWriter((request, response) -> {
                    if (request.getRequestURI().startsWith("/h2-console")) {
                        response.setHeader("X-Frame-Options", "SAMEORIGIN");
                    }
                }))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/h2-console/**").permitAll()
                .requestMatchers("/swagger-ui.html").permitAll()
                .requestMatchers("/swagger-ui/**").permitAll()
                .requestMatchers("/api-docs/**").permitAll()
                .requestMatchers("/v3/api-docs/**").permitAll()
                .anyRequest().permitAll()   // 临时
                //.anyRequest().authenticated()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    /**
     * 配置认证管理器
     *
     * &lt;p&gt;AuthenticationManager是Spring Security认证体系的核心接口，负责:&lt;/p&gt;
     * &lt;ul&gt;
     *   &lt;li&gt;验证用户提供的认证信息&lt;/li&gt;
     *   &lt;li&gt;在认证成功时创建已认证的Authentication对象&lt;/li&gt;
     *   &lt;li&gt;在认证失败时抛出AuthenticationException&lt;/li&gt;
     * &lt;/ul&gt;
     *
     * &lt;p&gt;认证流程：&lt;/p&gt;
     * &lt;ol&gt;
     *   &lt;li&gt;收集用户提供的认证信息(如用户名密码)&lt;/li&gt;
     *   &lt;li&gt;验证信息的有效性&lt;/li&gt;
     *   &lt;li&gt;验证成功则创建认证令牌&lt;/li&gt;
     *   &lt;li&gt;验证失败则抛出相应异常&lt;/li&gt;
     * &lt;/ol&gt;
     *
     * @param authConfig 包含认证配置信息的对象
     * @return Spring Security使用的AuthenticationManager实例
     * @throws Exception 如果获取AuthenticationManager时发生错误
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    /**
     * 配置密码编码器
     *
     * &lt;p&gt;使用BCrypt算法进行密码加密和验证。BCrypt具有以下特点:&lt;/p&gt;
     * &lt;ul&gt;
     *   &lt;li&gt;自动盐值(Salt): 每次加密使用不同的盐值，增加安全性&lt;/li&gt;
     *   &lt;li&gt;自适应性: 可通过工作因子调整加密强度&lt;/li&gt;
     *   &lt;li&gt;慢哈希: 刻意减缓加密速度，防止暴力破解&lt;/li&gt;
     *   &lt;li&gt;安全存储: 将盐值和哈希结果一起存储&lt;/li&gt;
     * &lt;/ul&gt;
     *
     * &lt;p&gt;应用场景：&lt;/p&gt;
     * &lt;ul&gt;
     *   &lt;li&gt;用户注册时加密密码&lt;/li&gt;
     *   &lt;li&gt;用户登录时验证密码&lt;/li&gt;
     *   &lt;li&gt;修改密码时加密新密码&lt;/li&gt;
     * &lt;/ul&gt;
     *
     * @return 使用BCrypt算法的PasswordEncoder实例
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}